#ifndef __VERTEX_DECALARATION_H__
#define __VERTEX_DECALARATION_H__

#include "GraphicsCompileConfig.h"

namespace Nezha
{
	enum
	{
		NZ_MAX_VERTEX_ATTRS = 16,

		NZ_MAX_TEX_UNITS = 8,

		NZ_MAX_COLOR_UNITS = 2
	};

	enum VertexSementic
	{
		VS_NONE = 0,
		VS_POSITION,
		VS_NORMAL,
		VS_TANGENT,
		VS_BINORMAL,
		VS_TEXCOORD,
		VS_COLOR,
		VS_BLENDINDICES,
		VS_BLENDWEIGHT,

		VS_MAX_SEMENTICS
	};

	enum VertexElementType
	{
		VET_NONE = 0,
		VET_FLOAT1,
		VET_FLOAT2,
		VET_FLOAT3,
		VET_FLOAT4,
		VET_SHORT1,
		VET_SHORT2,
		VET_SHORT3,
		VET_SHORT4,
		VET_COLOR,
		VET_HALF1,
		VET_HALF2,
		VET_HALF3,
		VET_HALF4,

		VET_MAX_ELEMENT_TYPES
	};

	struct GRAPHICS_ENTRY VertexElement
	{
		u16 StreamIndex;
		u32 Offset;
		VertexSementic Sementic;
		VertexElementType Type;
		u16 UsageIndex;
	};

	class GRAPHICS_ENTRY VertexDeclaration
	{
	public:
		VertexDeclaration();
		virtual ~VertexDeclaration();

		u32 numElements() const
		{
			return mElements.size();
		}

		bool hasElement(VertexSementic vs) const
		{
			return getElement(vs) != NULL;
		}

		const VertexElement* getElement(u32 i) const
		{
			NZ_ASSERT(i < numElements());

			return &mElements[i];
		}

		const VertexElement* getElementByVS(VertexSementic vs, u32 index = 0) const;

		/** add an element and self compute offset.
		*/
		const VertexElement* addElement(u32 streamIndex, VertexSementic sementic, VertexElementType vt,
			u32 usageIndex, bool updateStride = true);

		/** just add an element.
		*/
		const VertexElement* addElement(u32 streamIndex, u16 offset, VertexSementic sementic, VertexElementType vt,
			u32 usageIndex, bool updateStride = true);

		u32 updateStride();

		u32 getStride() const
		{
			return mStride;
		}

		/** clear all elements. */
		void clear();

		VertexDeclaration& operator = (const VertexDeclaration& vd);

		static u8 ElementTypeCount(VertexElementType vt);
		static u8 ElementUnitSize(VertexElementType vt);
		static u8 ElementTypeSize(VertexElementType vt);

	protected:
		u16 computeOffset(u32 index);

		typedef PArray<VertexElement> VEList;
		VEList mElements;
		u32 mStride;

	private:
		static u8 msElementTypeCount[VET_MAX_ELEMENT_TYPES];
		static u8 msElementUnitSize[VET_MAX_ELEMENT_TYPES];
		static u8 msElementTypeSize[VET_MAX_ELEMENT_TYPES];
	};

}//end namespace Nezha

#endif//end __VERTEX_DECALARATION_H__